package com.mindata.blockchain.common;

import cn.hutool.core.io.FileUtil;
import com.google.common.base.Preconditions;
import com.mindata.blockchain.socket.common.Const;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.io.File;

/**
 * 系统配置参数
 * User: jasperxgwang
 * Date: 2018-7-31 16:03
 */
@Slf4j
@Configuration
public class SystemConfig {

    /**
     * 节点的唯一标志
     */
    @Value("${peer.app.appId}")
    private String appId;
    /**
     * 该客户的唯一标志
     */
    @Value("${peer.app.name}")
    private String name;

    @Value("${peer.listen.ip:" + Const.SERVER + "}")
    private String ip;
    @Value("${peer.listen.port:" + Const.PORT + "}")
    private int port;

    /**
     * 是否单节点启动，测试情况使用
     */
    @Value("${peer.singeNode:" + Const.SINGE_NODE + "}")
    private boolean singeNode;

    /**
     * 共识算法
     */
    @Value("${block.consensus.type:" + Const.PBFT + "}")
    private String consensusType;

    /**
     * 管理后台
     */
    @Value("${peer.app.managerUrl:" + Const.MANAGER_URL + "}")
    private String managerUrl;

    /**
     * 最大指令池，-1 默认不限制
     */
    @Value("${peer.instruction.maxPoolSize:-1}")
    private int maxPoolSize;

    /**
     * 单个区块最大打包指令数，-1 默认不限制
     */
    @Value("${peer.instruction.packageLimitSize:200}")
    private int packageLimitSize;

    /**
     * 是否对区块解析
     */
    @Value("${block.analysis.execute:true}")
    private boolean blockAnalysisExec;

    @Value("${block.analysis.sqlite:true}")
    private boolean sqliteDb;
    @Value("${block.analysis.mysql:false}")
    private boolean mysqlDb;

    @Value("${block.db.dbPath:./database}")
    private String dbPath;

    @Value("${block.db.rocksDB:true}")
    private boolean blockRocksDB;

    @Value("${block.db.levelDB:false}")
    private boolean blockLevelDB;

    @Value("${raft.dataPath:" + Const.RAFTLOGDIR + "}")
    private String raftDataPath;
    @Value("${raft.server:" + Const.RAFTSERVERPORT + "}")
    private String raftLocalServer;

    @PostConstruct
    public void check() {
        if (StringUtils.isBlank(consensusType)) {
            log.warn("共识算法未配置，采用默认算法:{}", ConsensusType.PBFT);
            consensusType = ConsensusType.PBFT.getValue();
        } else {
            Preconditions.checkNotNull(ConsensusType.fromValue(consensusType), "共识算法配置错误");
        }

        Preconditions.checkArgument(!(maxPoolSize > 0 && maxPoolSize < 5000), "最大指令池最小必须为5000");

        log.info("SystemConfig [peer.app.appId]:{}", getAppId());
        log.info("SystemConfig [peer.app.name]:{}", getName());
        log.info("SystemConfig [peer.app.managerUrl]:{}", getManagerUrl());
        log.info("SystemConfig [peer.listen.ip]:{}", getIp());
        log.info("SystemConfig [peer.listen.port]:{}", getPort());
        log.info("SystemConfig [peer.singeNode]:{}", isSingeNode());

        log.info("SystemConfig [block.db.dbPath]:{}", getBlockDbPath());
        log.info("SystemConfig [block.db.rocksDB]:{}", isBlockRocksDB());
        log.info("SystemConfig [block.db.levelDB]:{}", isBlockLevelDB());
        log.info("SystemConfig [raft.dataPath]:{}", getRaftDataPath());
        log.info("SystemConfig [raft.server]:{}", getRaftLocalServer());

        log.info("SystemConfig [peer.instruction.maxPoolSize]:{}", getMaxPoolSize());
        log.info("SystemConfig [peer.instruction.packageLimitSize]:{}", getPackageLimitSize());

        log.info("SystemConfig [block.consensus.type]:{}", getConsensusType());

        log.info("SystemConfig [block.analysis.execute]:{}", isBlockAnalysisExec());
        log.info("SystemConfig [block.analysis.sqlite]:{}", isSqliteDb());
        log.info("SystemConfig [block.analysis.mysql]:{}", isMysqlDb());
    }

    public String getRaftLocalServer() {
        return raftLocalServer;
    }

    public ConsensusType getConsensusType() {
        return ConsensusType.fromValue(consensusType);
    }

    public String getManagerUrl() {
        return managerUrl;
    }

    public int getMaxPoolSize() {
        return maxPoolSize;
    }

    public int getPackageLimitSize() {
        return packageLimitSize;
    }


    public boolean isBlockAnalysisExec() {
        return blockAnalysisExec;
    }

    public boolean isSqliteDb() {
        return sqliteDb;
    }

    public boolean isMysqlDb() {
        return mysqlDb;
    }

    public boolean isSingeNode() {
        return singeNode;
    }

    public String getAppId() {
        return appId;
    }

    public String getName() {
        return name;
    }

    public String getIp() {
        if (ip.equals(Const.SERVER)) {
            ip = CommonUtil.getLocalIp();
        }
        return ip;
    }

    public boolean isBlockRocksDB() {
        return blockRocksDB;
    }

    public boolean isBlockLevelDB() {
        return blockLevelDB;
    }

    public int getPort() {
        return port;
    }

    public String getDbPath() {
        return dbPath;
    }

    public String getRaftDataPath() {
        String dbType = isBlockLevelDB() ? "raft-levelDB" : "raft-rocksDB";
        File file = FileUtil.mkdir(raftDataPath);
        return file.getAbsolutePath() + File.separator + dbType;
    }

    public String getBlockDbPath() {
        String dbType = isBlockLevelDB() ? "levelDB" : "rocksDB";
        File file = FileUtil.mkdir(getDbPath());
        return file.getAbsolutePath() + File.separator + dbType;
    }
}
